package lxs.tool.liberator.system.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import lombok.SneakyThrows;
import lxs.tool.liberator.common.exception.ConnectException;
import lxs.tool.liberator.work.pojo.Project;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Value("${spring.datasource.druid.driver-class-name}")
    private String driver;
    @Value("${spring.datasource.druid.url}")
    private String url;
    @Value("${spring.datasource.druid.username}")
    private String username;
    @Value("${spring.datasource.druid.password}")
    private String password;
    private static final String mysqlUrl = "jdbc:{db-type}://{db-ip}:{host}/{dbname}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
    private static final String oracleUrl = "jdbc:{{db-type}}:thin:@{db-ip}:{host}:{dbname}";
    private static final String oracleDriver = "oracle.jdbc.driver.OracleDriver";

    public static Map<Object, Object> dataSourcesMap = new HashMap<>();
    public static Map<String, Statement> statementMap = new HashMap<>();


    @Override
    protected Object determineCurrentLookupKey() {
        return DbHolder.get();
    }

    @Override
    protected DataSource determineTargetDataSource() {
        return super.determineTargetDataSource();
    }

    public void switchSource(String dataSource) {
        DbHolder.set(dataSource);
        this.afterPropertiesSet();
    }

    public void addDataSource(String key, DataSource dataSource) {
        dataSourcesMap.put(key, dataSource);
    }

    public static void removeDataSource(String key) {
        dataSourcesMap.remove(key);
        statementMap.remove(key);
    }

    static class ConnectionThread implements Runnable {
        private final DruidDataSource dataSource;

        public ConnectionThread(DruidDataSource dataSource) {
            this.dataSource = dataSource;
        }

        private DruidPooledConnection connection;

        @SneakyThrows
        @Override
        public void run() {
            connection = dataSource.getConnection();
        }

        public DruidPooledConnection getConnection() {
            return connection;
        }

        public void waitConnect(long time) throws InterruptedException {
            Thread.sleep(time);
        }
    }

    // 调用此方法，切换数据源
    public void switchTo(Project project) throws Exception {
        if (!DynamicDataSource.dataSourcesMap.containsKey(project.getId())) {
            String u = project.getDbType().equals("mysql") ? mysqlUrl : oracleUrl;
            u = u.replace("{db-type}", project.getDbType());
            u = u.replace("{db-ip}", project.getDbIp());
            u = u.replace("{host}", project.getDbHost());
            u = u.replace("{dbname}", project.getDbname());
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setUrl(u);
            dataSource.setUsername(project.getDbUsername());
            dataSource.setPassword(project.getDbPassword());
            if (project.getDbType().equals("mysql")) {
                dataSource.setDriverClassName(driver);
            } else {
                dataSource.setDriverClassName(oracleDriver);
            }
            dataSource.setConnectionErrorRetryAttempts(0);
            dataSource.setBreakAfterAcquireFailure(true);
            DruidPooledConnection connection;
            ConnectionThread connectionThread = new ConnectionThread(dataSource);
            Thread thread=new Thread(connectionThread);
            thread.start();
            connectionThread.waitConnect(3000L);
            connection = connectionThread.getConnection();
            if (connection==null) {
                throw new ConnectException(project.getName() + "项目数据库连接异常:确保数据库信息正确并允许远程连接");
            }
            this.addDataSource(project.getId(), dataSource);
            statementMap.put(project.getId(), connection.createStatement());
        }
        DbHolder.set(project.getId());
    }

    private String getHostIp() {
        try {
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = allNetInterfaces.nextElement();
                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress ip = addresses.nextElement();
                    if (ip instanceof Inet4Address
                            && !ip.isLoopbackAddress() //loopback地址即本机地址，IPv4的loopback范围是127.0.0.0 ~ 127.255.255.255
                            && !ip.getHostAddress().contains(":")) {
                        System.out.println("本机的IP = " + ip.getHostAddress());
                        return ip.getHostAddress();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void clear() {
        DbHolder.remove();
        this.afterPropertiesSet();
    }

    public void switchBack() {
        this.clear();
    }


    public void execute(String sql) throws SQLException {

        statementMap.get(DbHolder.get()).execute(sql);
    }

    public ResultSet executeQuery(String sql) throws SQLException {

        return statementMap.get(DbHolder.get()).executeQuery(sql);

    }
}
